gusucode.com > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序 > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序/code/Src/Client/scwinlib/SCZoomBox.cpp

    //Download by http://www.NewXing.com
/*
*	This file is part of the EMFexplorer projet.
*	Copyright (C) 2004 Smith Charles.
*
*	This library is free software; you can redistribute it and/or
*	modify it under the terms of the GNU Lesser General Public
*	License as published by the Free Software Foundation; either
*	version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
*
*	Extension: for commercial use, apply the Equity Public License, which
*	adds to the normal terms of the GLPL a condition of donation to the author.
*   If you are interested in support for this source code,
*   contact Smith Charles <smith.charles@free.fr> for more information.
*/

#include "stdafx.h"
#include "SCZoomBox.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define AM_DELAY_UPDATE_NOTIFY	(WM_USER + 1)	// self-posted message

// The caller can use an extended range of zoom values (0..10000 instead of 0..100)
// so that float usage is avoided or limited
// (hence a zoom of 51.2% is represented as 5120)
#define SC_DEFAULT_MULTIPLIER		1 // by default, dont use this technique

#define SC_ZOOMCMB_MAX_DISPLAY_DIGITS		7 // ####.##

#ifdef _UNICODE
	inline double sc_tatof(LPCTSTR lpsz)
	{
		double dValue;
		_stscanf(lpsz, _T("%lf"), &dValue);
		return dValue;
	}
#else
	#define	sc_tatof(d) atof(d)
#endif

/////////////////////////////////////////////////////////////////////////////
// CSCZoomBox

CSCZoomBox::CSCZoomBox():
	m_bTrapEnter(FALSE),
	m_pZoomDefaults(NULL),
	m_usZoomCount(0),
	m_bRestyled(FALSE),
	m_bUserText(FALSE)
{
	SCReset();
}

void CSCZoomBox::SCReset()
{
	m_iFloatMultiplier = SC_DEFAULT_MULTIPLIER;
	m_iMin = 1*SC_DEFAULT_MULTIPLIER;
	m_iMax = 100*SC_DEFAULT_MULTIPLIER;
	m_iValue = 100*SC_DEFAULT_MULTIPLIER;
}

CSCZoomBox::~CSCZoomBox()
{
}

BEGIN_MESSAGE_MAP(CSCZoomBox, CComboBox)
	//{{AFX_MSG_MAP(CSCZoomBox)
	ON_WM_CREATE()
	ON_WM_CTLCOLOR()
	ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange)
	ON_CONTROL_REFLECT(CBN_KILLFOCUS, OnKillFocus)
	ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnEditChange)
	ON_MESSAGE( AM_DELAY_UPDATE_NOTIFY, OnSCDelayUpdateAndNotify )
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSCZoomBox utilities

//
// Multiplier is changing: adjust the current values accordingly.
//
void CSCZoomBox::SCSetFloatMultiplier(int iMultiplier)
{
	ASSERT(iMultiplier>0);
	ASSERT(m_iFloatMultiplier>0);

	m_iMin = MulDiv(m_iMin, iMultiplier, m_iFloatMultiplier);
	m_iMax = MulDiv(m_iMax, iMultiplier, m_iFloatMultiplier);
	m_iValue = MulDiv(m_iValue, iMultiplier, m_iFloatMultiplier);

	m_iFloatMultiplier = iMultiplier;
}

//
// Use the array of zoom entries to fill the combobox if the window exists
//
// Entry values are premultiplied (percentage * FloatMultiplier).
// Since the end-user sees en enters floats, long entries are converted to floats
// except for special (negative) values.
//
BOOL CSCZoomBox::SCFillCombo()
{
	if (!IsWindow(m_hWnd) || !m_pZoomDefaults)
		return FALSE;

	ResetContent();
	CString strZoom;
	for (USHORT i=0; (i<m_usZoomCount); i++)
	{
		int iValue = m_pZoomDefaults[i].ze_iValue;
		ASSERT((iValue<0) || (iValue>=m_iMin && iValue<=m_iMax));
		strZoom = m_pZoomDefaults[i].ze_lpszText;
		if (strZoom.IsEmpty())
		{// default presentation
			strZoom = SCValue2String(iValue);
		}
		int nIndex = AddString(LPCTSTR(strZoom));
		if (nIndex>=0)
		{
			SetItemData(nIndex, (DWORD)iValue);
		}
	}
	SCUpdateEditBox();
	return TRUE;
}

//
// Return the index of iValue if any
//
int CSCZoomBox::SCIndexFromValue(int iValue)
{
	for (USHORT i=0; (i<m_usZoomCount); i++)
	{
		if (iValue == (int)GetItemData(i))
			return (int)i;
	}
	return CB_ERR;
}

//
// Return a visual representation of a percentage
//
CString CSCZoomBox::SCValue2String(int iValue)
{
	ASSERT(m_iFloatMultiplier>0);

	// build the format according to precision: something like "%.2f"
	int iPrecision = (int)log10(m_iFloatMultiplier);
	CString strFormat;
	strFormat.Format(_T("%%.%df"), iPrecision);

	CString strValue;
	strValue.Format(strFormat, ((float)iValue)/m_iFloatMultiplier);
	if (iPrecision)
	{// remove trailing zeros after decimal point (2 steps required)
		strValue.TrimRight(_T("0"));
		strValue.TrimRight(_T("."));
	}

	return strValue;
}

//
// Force the current value to be the one passed in argument.
// Values ares expected in the float format but are converted to int.
// (Don't call this for special values)
//
void CSCZoomBox::SCSetCurValue(int iZoom)
{
	// adjust the value
	if (iZoom<m_iMin)
	{
		m_iValue = m_iMin;
	} else
	if (iZoom>m_iMax)
	{
		m_iValue = m_iMax;
	} else
		m_iValue = iZoom;

	// attempt to format an show
	SCUpdateEditBox();
}

//
// Force a value to show in the edit box.
//
void CSCZoomBox::SCSelectValue(int iValue)
{
	for (USHORT i=0; (i<m_usZoomCount); i++)
	{
		if (iValue==m_pZoomDefaults[i].ze_iValue)
		{
			m_iValue = iValue;
			SetCurSel(i);
			break;
		}
	}

	// Make as if someone typed in the value (which must be valid)
	if (iValue>=m_iMin && iValue<=m_iMax)
	{
		m_iValue = iValue;
		SCUpdateEditBox();
	}
}

//
// Display the ext corresponding to m_iValue.
//
inline void CSCZoomBox::SCRestoreValue()
{
	if (m_iValue<0)
		SetCurSel(SCIndexFromValue(m_iValue));
	else
		SCUpdateEditBox();
}

inline BOOL SCIsNum(TCHAR ch)
{
	if ((ch>=_T('0') && ch<=_T('9')) || _T('-')==ch || _T('+')==ch)
		return TRUE;
	return FALSE;
}

//
// Force the edit box's text to become the new value.
//
void CSCZoomBox::SCEatValue()
{
	if (!m_bUserText)
		return;
	m_bUserText = FALSE;

	// Get the value's text
	CString strText;
	GetWindowText(strText);
	strText.TrimLeft(_T(" "));
	
	if (0==strText.GetLength())
	{// restore previous value
		SCRestoreValue();
		return;
	}

	// Compute it
	if (SCIsNum(strText[0]))
	{
		int iValue = (int)(sc_tatof(LPCTSTR(strText))*m_iFloatMultiplier);
		if (iValue==m_iValue)
		{// refresh
			SCUpdateEditBox();
		} else
		{
			// Store new value
			SCSetCurValue(iValue);
			
			// Notify parent
			SCNotifyParent();
		}
	} else
	{
		int iStrIdx = FindString(-1, strText);
		if (iStrIdx!=CB_ERR)
		{// select from text
			SetCurSel(iStrIdx);
			OnSelchange();
		} else
			SCRestoreValue(); // restore previous value
	}
}

//
// Store an array of zoom information
//
void CSCZoomBox::SCSetDefaultList(PSCZoomEntry pZooms, USHORT usCount)
{
	m_pZoomDefaults = pZooms;
	m_usZoomCount = usCount;

	// Update combo, if possible
	SCFillCombo();
}

///
/// Always display percent sign in edit box.
///
void CSCZoomBox::SCUpdateEditBox()
{
	// bail out in case of special value
	if (m_iValue<0)
		return;
	// format an show
	CString strText = SCValue2String(m_iValue) + _T("%");
	SetWindowText(strText);
}

///
/// Tell the parent that selection has changed.
///
void CSCZoomBox::SCNotifyParent()
{
	CWnd *pParent = GetParent();
	
	ASSERT(pParent);
	if (!pParent)
		return;

	NMHDR nmhdr;
	nmhdr.code = CBN_EDITCHANGE;
	nmhdr.hwndFrom = m_hWnd;
	nmhdr.idFrom = GetDlgCtrlID();
	pParent->SendMessage(WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
}

/////////////////////////////////////////////////////////////////////////////
// CSCZoomBox message handlers

////////////////////////////////////////////////
// Bad, bad, bad land! (though the code is good)
//	
// Warning: it may not be called, so apply settings in dialog template or
// in the call to CreateEx
///
/// Remove sorting attribute before creation.
///
BOOL CSCZoomBox::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CComboBox::PreCreateWindow(cs))
		return FALSE;

	cs.style &= ~CBS_SORT;

	return TRUE;
}

// Warning: A problem in dialog template created classes (CListBox, CEdit, and so on
// created by AppStudio) is that OnCreate is not called.
///
/// Limit text and fill the listbox part with values.
///
int CSCZoomBox::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CComboBox::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	SCInitCombo();
	return 0;
}
////////////////////////////////////////////////

// To call in initdialog
BOOL CSCZoomBox::SCInitCombo() 
{
	LimitText(SC_ZOOMCMB_MAX_DISPLAY_DIGITS); // ####.##

	// Fill combobox with default values
	SCFillCombo();
	return TRUE;
}

///
/// Enforcing the ES_WANTRETURN style.
///
HBRUSH CSCZoomBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	if (!m_bRestyled)
	{
		m_bRestyled = TRUE;
		if (nCtlColor == CTLCOLOR_EDIT)
		{
			// The Edit control
			if (0==(pWnd->GetStyle() & ES_WANTRETURN))
				pWnd->ModifyStyle(0, ES_WANTRETURN);
		}
	}
	return CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
}

////////////////////////////////////////////
/// Bad land! it may not be called in dialog.
///
/// Trap the enter key for special processing.
///
BOOL CSCZoomBox::PreTranslateMessage(MSG* pMsg)
{
	if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_RETURN))
	{
		// When the enter key is hit in the ComboBox, we want to get the string
		// and notify the parent.
		if ((pMsg->lParam & 0x40000000) == 0)   // Not a repeat.
		{
			// Get the value
			SCEatValue();
		}
		if (m_bTrapEnter)
			return TRUE;
	}

	return CComboBox::PreTranslateMessage(pMsg);
}
////////////////////////////////////////////

///
/// Called when a new list item is selected.
///
void CSCZoomBox::OnSelchange() 
{
	m_bUserText = FALSE;
	// Validate the selected text
	int iIdx = GetCurSel();
	if (CB_ERR!=iIdx)
	{// actual selection: get the new value from the list
		int iValue = (int)GetItemData(iIdx);
		if (iValue>=0)
		{
			CString strText;
			GetLBText(iIdx, strText);
			// Won't cause notification, but editbox will be erased
			SCSetCurValue((int)(sc_tatof(LPCTSTR(strText))*m_iFloatMultiplier));
		} else
		{// Store special value "as is"
			m_iValue = iValue;
		}
			
		// At this time the edit portion of the combo box has not been updated
		// So we will delay update and parent notification
		PostMessage(AM_DELAY_UPDATE_NOTIFY);
	} else
		SCNotifyParent(); 	// Just notify the parent
}

///
/// Delayed processing of an actual selection.
///
LRESULT CSCZoomBox::OnSCDelayUpdateAndNotify(WPARAM wParam, LPARAM lParam)
{
	// format an show current zoom
	SCUpdateEditBox();

	// Notify parent
	SCNotifyParent();

	return 0L;
}

void CSCZoomBox::OnKillFocus()
{
	// TODO: check text
	SCEatValue();
}

void CSCZoomBox::OnEditChange()
{
	m_bUserText = TRUE;
}